#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

const int defaultnum = 20;

template <class T>
class Ringqueue
{
  void P(sem_t &sem)
  {
    sem_wait(&sem);
  }

  void V(sem_t &sem)
  {
    sem_post(&sem);
  }

  void Lock(pthread_mutex_t mutex)
  {
    pthread_mutex_lock(&mutex);
  }
  void Unlock(pthread_mutex_t mutex)
  {
    pthread_mutex_unlock(&mutex);
  }

public:
  Ringqueue(int num = defaultnum)
      : _ringqueue(num), _cap(num), _c_step(0), _p_step(0)
  {
    sem_init(&_cdata_sem, 0, 0);
    sem_init(&_pspace_sem, 0, num);

    pthread_mutex_init(&_c_mutex, nullptr);
    pthread_mutex_init(&_p_mutex, nullptr);
  }

  void push(const T &data)
  {
    P(_pspace_sem);
    Lock(_p_mutex);
    _ringqueue[_p_step] = data;
    // 向后移动下标，并且保证环形特征
    _p_step++;
    _p_step %= _cap;
    Unlock(_p_mutex);
    V(_cdata_sem);
  }

  void pop(T *data)
  {
    P(_cdata_sem);
    Lock(_c_mutex);
    *data = _ringqueue[_c_step];
    // 向后移动下标，并且维持环形特征
    _c_step++;
    _c_step %= _cap;
    Unlock(_c_mutex);
    V(_pspace_sem);
  }

  ~Ringqueue()
  {
    sem_destroy(&_cdata_sem);
    sem_destroy(&_pspace_sem);

    pthread_mutex_destroy(&_c_mutex);
    pthread_mutex_destroy(&_p_mutex);
  }

private:
  std::vector<T> _ringqueue; // 环形队列
  int _cap;
  int _c_step; // 消费的下标
  int _p_step; // 生产的下标

  // 生产者和消费者关注的数据资源
  sem_t _cdata_sem;
  sem_t _pspace_sem;

  // 为生产者和消费者提供各自自己的互斥锁
  pthread_mutex_t _c_mutex;
  pthread_mutex_t _p_mutex;
};